#pragma once

#include <iostream>
#include <vector>
#include <semaphore.h>
#include <cassert>

static const int gmaxcap = 5;

template <class T>
class RingQueue
{
public:
    RingQueue(const int &cap = gmaxcap)
        : _queue(cap), _cap(cap)
    {
        int n = sem_init(&_spaceSem, 0, _cap);
        assert(n == 0);
        n = sem_init(&_dataSem, 0, 0);
        assert(n == 0);
        _producerStep = _consumerStep = 0;
    }
    void P(sem_t &sem)
    {
        int n = sem_wait(&sem);
        assert(n == 0);//if
        (void)n;
    }
    void V(sem_t &sem)
    {
        int n = sem_post(&sem);
        assert(n == 0);
        (void)n;
    }
    //生产者
    void push(const T &in)
    {
        P(_spaceSem); // 申请到了空间信号量，意味着，生产者可以正常生产。
        _queue[_producerStep++] = in;
        _producerStep %= _cap;
        V(_dataSem);
    }
    //消费者
    void pop(T *out)
    {
        P(_dataSem); // 申请到了数据信号量，意味着，消费者可以正常消费
        *out = _queue[_consumerStep++];
        _consumerStep %= _cap;
        V(_spaceSem);
    }
    ~RingQueue()
    {
        sem_destroy(&_spaceSem);
        sem_destroy(&_dataSem);
    }

private:
    std::vector<int> _queue; // 数组模拟环形队列
    int _cap;                // 环形队列容量
    sem_t _spaceSem;         // 生产者，想生产，看重的是空间资源
    sem_t _dataSem;          // 消费者，想消费，看重的是数据资源
    int _producerStep;       // 生产数据的下标
    int _consumerStep;       // 消费数据的下标
};